本文共 8471 字,大约阅读时间需要 28 分钟。
查看专栏其它文章:
本人是个新手,写下博客用于自我复习、自我总结。 如有错误之处,请各位大佬指出。 学习资料来源于:尚硅谷
所谓“脚手架”,就是用来帮助程序员快速创建一个基于xxx库的模板项目。它包含了所有需要的配置,指定好了所有的依赖,并可以直接安装/编译/运行一个简单效果。react提供了一个用于创建react项目的脚手架库: create-react-app
在继续下面的内容前,请确保电脑中已安装了Node.JS。如果未安装,可直接去其下载。安装步骤很简单。
如果对Node.JS感兴趣,可以查阅我的文章:
检测是否安装成功:
创建项目
以下步骤可以在命令行中执行,也可以选择在各个开发工具中执行。
开发工具的命令行在左下角的Terminal ( Webstorm 、IDEA )
步骤一: npm install -g create-react-app步骤二:create-react-app hello-react (这可能需要很长时间,请耐心等待)
随后它也会告诉你相关命令。( 我们想运行项目之后输入 npm start 即可 )
步骤三:cd hello-react
步骤四:npm start
然后就会自动跳转进页面。如果未跳转,在命令行中点击链接也可以。
到这里基础的项目已经构建完成。想运行项目就 npm start。补充说明: 对于Google Chrome,如果新建的react项目,执行npm start后控制台报错: Uncaught TypeError: Cannot read property ‘forEach‘ of undefined,看该篇文章就可解决问题:
如果开发工具不识别 JSX (出现红色波浪线),我们可以这样设置:
项目结构
建好项目后,简单介绍一下项目结构:
对于普通的学习者来说,我们主要知道 src 中的文件该如何操作即可。(将在后续叙述)简单介绍一下还应该了解的部分内容:
gitignore 会在打包的时候帮我们忽略一些不想去编译打包的文件,比如 node_modules、debug、各种开发工具的文件夹(比如.idea)等等。
package.json 主要提供项目的一些相关标识(必不可少的就是name和version)、记录一些依赖信息(必不可少的就是依赖包和它的版本号)、记录当前项目如何运行和打包。
项目构建好后,清空src中的初始文件,然后去建我们自己的文件。
首先我们可以建一个components文件夹用来存放组件,然后其中的所有文件全是jsx文件,用来表示它是组件。然后在src层存放css文件、js文件等。(详细结构需要看个人习惯)
jsx组件中应该写什么内容?
和之前学习的语法一样,但是需要import React,还需要 export 暴露出去。
import React from 'react'export default class App extends React.Component { render () { return ( ) }}
这就是最基本的结构。如果我们想引入自己的资源文件,依然选用 import 导入即可。现在举个简单的例子,展示一张图片:( app.jsx )
import React from 'react'import logo from '../logo.svg'export default class App extends React.Component { render () { return () }}
组件设置好了之后,还需要设置其他内容:
入口文件 index.js 中应该写什么内容?
它的写法比较固定:import React 和 ReactDOM ,然后 import 组件,最后和之前语法一样,用 render 渲染。
import React from 'react'import ReactDOM from 'react-dom'import App from './components/app'ReactDOM.render(, document.getElementById('root'))
在这里推荐 jsx 组件名小写,但是导入时首字母大写。
而在这里为什么 document.getElementById('root')
,id 为什么是 root ?
现在就可以使用 npm start 看一下效果了。
补充说明: 在运行时为什么会去选择 public 下的 index.html 文件,又为什么会选择 src 文件夹下的 index.js 作为入口文件呢?
这是因为 React 帮我们配置好了这部分内容。
在每个项目中,都可以看到 node_modules 文件夹,里面存放了项目需要的所有依赖。在这里就有我们想要的答案。
在最初创建项目时,create-react-app 把 webpack、babel 等配置都封装到了依赖项目 react-script 中,所以你会发现在项目的 package.json 中明明没有多少依赖包,结果 node_modules 里有那么多依赖的原因。你可以在项目下运行 npm run eject,被隐藏的配置文件就会暴露到项目根路径下。当你npm start
时,它会启动webpack-dev-server,会加载react-script项目config文件夹下的配置(paths.js) 当我们打开 paths.js 就可以看到,在里面定义了请求的默认转发路径是public文件夹,自然就找到了public下的index.html,同理index.js也是。 如果想要添加样式,就可以在组件中添加类名,然后在 index.css 中添加样式。同时不要忘记在入口文件 index.js 中导入样式
( index.css )
.logo { width: 200px; height: 200px;}.title{ color: red; font-size: 25px;}
( app.jsx )
import React from 'react'import logo from '../logo.svg'export default class App extends React.Component { render () { return () }}react app 组件
( index.js )
import React from 'react'import ReactDOM from 'react-dom'import App from './components/app'import './index.css'ReactDOM.render(在这里需要说明的是,在组件render中放入html时:, document.getElementById('root'))
在html中,设置类是<p class="xxx"></p>
,
现在要将它们全部改成<p className="xxx"></p>
如果在html中涉及到了style:<p style='display:none'></p>
,
现在要将它们全部改成<p style={ {display: 'none'}}></p>
除此以外,项目能够实时更新(即 只要一次 npm start ,之后每次修改内容,项目都会自动重新编译打包)
( 以下内容中将不包括CSS代码 )
在有了之前的基础后,再简单说一下所谓 组件化编码 的步骤( 编码过程主要看个人习惯 ):
拆分组件: 拆分界面,抽取组件
实现静态组件: 使用组件实现静态页面效果
实现动态组件
① 动态显示初始化数据 ② 交互功能(从绑定事件监听开始)那无论是如何编写代码,拆分组件都应该是需要的,方便后续创建组件和管理。
在本次练习中,将完成以下界面及其功能。在这里选择将其拆分成以下几个组件。
通过拆分得到,根组件 app 和它的子组件 add 和 list 。list 组件的子组件为 item。因此src结构: 因为 app 是根组件,所以在 index.js 中:import React from 'react'import ReactDOM from 'react-dom'import App from './components/app/app'ReactDOM.render(, document.getElementById('root'))
整体的css文件可以放在这里:
调用的时候去 index.html 中:<link rel="stylesheet" href="/css/xxx.css">
即可。 拆分好之后就需要考虑每个组件中的内容:在项目中涉及到了哪些属性和方法,分别放在哪个组件中比较合适。显然在本例中,所有属性和方法全部放在 app 组件中,再传递出去最合适。因为 app 组件是根组件。如果 add 组件存放用户名等属性,需要在 list 中展示,那还需要先传递给 app 组件再传递给 list 组件。对于方法也是一样的,因为如果想要提交,需要对属性做添加操作,还是需要找到属性。因此放在根组件中合适。
(先不考虑其他传递方式,就是最基本的传递。组件间通信将在下篇文章叙述)
构思好之后,第二步,所谓的静态组件,就是先去实现 html 和 css 部分,看能否正常显示,因为如果不能正常显示,之后做的一切也都没意义。当页面能显示后,我们就可以做第三步,动态组件:定时器、提交效果、删除效果等等效果。
对于这整部分内容的代码,在使用上全是以前文章中用到的用法。为了更加直观和简洁,在这里就直接演示最终代码了。和以前的唯一区别,需要注意的是:不要忘记 import 。
app.jsx
import React from 'react'import CommentAdd from '../comment-add/comment-add'import CommentList from '../comment-list/comment-list'class App extends React.Component { //构造函数 constructor (props) { super(props) this.state = { //初始化 comments: [] } //绑定 add不用绑是因为使用了箭头函数 this.delete = this.delete.bind(this) } componentDidMount () { //模拟异步获取数据 setTimeout(() => { const comments = [ { username: "Tom", content: "ReactJS好难啊!", id: Date.now() }, { username: "JACK", content: "ReactJS还不错!", id: Date.now() + 1 } ] this.setState({ comments}) }, 1000) } add = (comment) => { let comments = this.state.comments comments.unshift(comment) this.setState({ comments }) } delete (index) { let comments = this.state.comments comments.splice(index, 1) this.setState({ comments }) } render () { return () }}export default App请发表对React的评论
comment-add.jsx
import React from 'react'import PropTypes from 'prop-types'class CommentAdd extends React.Component { //构造函数 constructor (props) { super(props) this.state = { //初始化 username: '', content: '' } //绑定 this.addComment = this.addComment.bind(this) this.changeUsername = this.changeUsername.bind(this) this.changeContent = this.changeContent.bind(this) } addComment () { // 根据输入的数据创建评论对象 let { username, content } = this.state let comment = { username, content } // 添加到comments中, 更新state this.props.add(comment) // 清除输入的数据 this.setState({ username: '', content: '' }) } changeUsername (event) { this.setState({ username: event.target.value }) } changeContent (event) { this.setState({ content: event.target.value }) } render () { return () }}CommentAdd.propTypes = { add: PropTypes.func.isRequired}export default CommentAdd
comment-list.jsx
import React from 'react'import PropTypes from 'prop-types'import CommentItem from '../comment-item/comment-item'import './commentList.css'class CommentList extends React.Component { constructor (props) { super(props) } render () { let comments = this.props.comments let display = comments.length > 0 ? 'none' : 'block' return () }}CommentList.propTypes = { comments: PropTypes.array.isRequired, delete: PropTypes.func.isRequired}export default CommentList评论回复:
暂无评论,点击左侧添加评论!!!
{ comments.map((comment, index) => { console.log(comment) return
}) }
comment-item.jsx
import React from 'react'import PropTypes from 'prop-types'import './commentItem.css'class CommentItem extends React.Component { constructor (props) { super(props) this.deleteComment = this.deleteComment.bind(this) } deleteComment () { let username = this.props.comment.username if (window.confirm(`确定删除${ username}的评论吗?`)) { this.props.delete(this.props.index) } } render () { let comment = this.props.comment return (
{ comment.username}说:
{
comment.content}转载地址:http://emyki.baihongyu.com/